home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-05-14 | 17.5 KB | 460 lines | [TEXT/3PRM] |
- module scrabble
-
-
- /* Original program written by Paul de Mast in the functional programming language Amanda.
- This program is the translated and adapted version to Clean.
- */
-
-
- import StdEnv
- import deltaEventIO, deltaDialog, deltaTimer, deltaWindow, deltaMenu, deltaFileSelect, deltaIOState, scrollList
- import board, graphics, state, language
- import Help
-
-
- /***************************************************************************************************************
- The Start rule creates the GUI of the scrabble game and the initial program state.
- ****************************************************************************************************************/
- Start :: *World -> *World
- Start world
- # (es,world) = OpenEvents world
- (fs,world) = openfiles world
- (aboutdialog,fs) = MakeAboutDialog "Scrabble" helpfilename fs help
- t0 = initstate fs
- (kind1,kind2,strength,t1) = (\t=:{player1,player2,strength}->(player1.kind,player2.kind,strength,t)) t0
- (tn,es) = StartIO [ MenuSystem
- [ scrabblemenu (kind1,kind2)
- , strengthmenu strength
- ]
- , TimerSystem
- [ Timer computerId Unable 0 computer
- ]
- , DialogSystem
- [ aboutdialog
- ]
- ] t1 [initialisestate,scrabblepanel,arbitrate] es
- world = CloseEvents es world
- world = closefiles tn.files world
- = world
-
-
- /***************************************************************************************************************
- The user request the placement of a word.
- ****************************************************************************************************************/
- placeword :: DialogInfo State (IOState State) -> (State,IOState State)
- placeword info t=:{ board
- , playmode
- , dimensions=(minx,maxx,miny,maxy)
- , player
- , player1
- , player2
- , letterbox
- , lexicon
- , random
- } io
- | lastword==""
- = arbitrate nt (drawplayerletters player newplayerletters (drawcommunication text io))
- with
- nt = {t2 & random=rs1,letterbox=restletterbox}
- t2
- | player==Player1 = {t1 & playmode= EndPlayer1
- , player1 = {t1.player1 & letters=newplayerletters,placedword=False}}
- | otherwise = {t1 & playmode= EndPlayer2
- , player2 = {t1.player2 & letters=newplayerletters,placedword=False}}
-
- text = [toString player+++exchanges_letters]
- (restletterbox,newplayerletters,rs1)
- = grab (playerletters++letterbox) 7 random
-
- | not (seek lexicon lastword)
- = OpenModalDialog (newwordspanel [lastword:unknownwords] info) t1 io
-
- | outsideboard
- = (t1,drawcommunication text io)
- with
- text = [ toString player+++":" : placement_error lastword (i+1,j+1) ]
-
- | not (isEmpty missingletters)
- = (t1,drawcommunication text io)
- with
- text = [ toString player+++":" : missing_letters_error missingletters ]
-
- | not possible
- = (t1,drawcommunication [ toString player+++":" : anonymous_placement_error ] io)
-
- | not (isEmpty unknownwords)
- = OpenModalDialog (newwordspanel unknownwords info) t1 io
-
- | otherwise
- = arbitrate nt ( drawplayerinfo player totalscore newplayerletters (
- drawcommunication text (
- redrawboard nb io)))
- with
- nt
- | player==Player1 = {nt1 & player1 = setplayer newplayerletters totalscore True nt1.player1
- , playmode = EndPlayer1}
- | otherwise = {nt1 & player2 = setplayer newplayerletters totalscore True nt1.player2
- , playmode = EndPlayer2}
- setplayer letters score placed player
- = {player & letters=letters,points=score,placedword=placed}
- nt1 = {t1 & letterbox = restletterbox
- , dimensions = newdimensions
- , board = nb
- , random = rs1
- }
- newplayerletters = remainingletters++replenishletters
- (restletterbox,replenishletters,rs1)
- = grab letterbox (7-length remainingletters) random
- text = nr_new_words_placed ((length newwords)+1) [lastword:newwords]
- where
- (x,y) = (\(PairCS (IntCS x) (IntCS y))->(x,y)) (GetControlState 100 info)
- direction = if (GetSelectedRadioItemId 1 info==201) Hor Ver
- lastword = GetEditText 200 info
- t1 = {t & direction=direction}
-
- (playerletters,playerscore)
- = playerinfo
- playerinfo
- | player==Player1 = (player1.letters,player1.points)
- | otherwise = (player2.letters,player2.points)
- newdimensions
- | direction==Hor = (min i minx, max (i+wordlength-1) maxx, min j miny, max j maxy)
- | otherwise = (min i minx, max i maxx, min j miny, max (j+wordlength-1) maxy)
-
- outsideboard = (direction==Hor && ((i+wordlength<minx)||(i>maxx+1)||(j<miny-1)||(j>maxy+1)))
- ||
- (direction==Ver && ((i<minx-1)||(i>maxx+1)||(j+wordlength<miny-1)||(j>maxy+1)))
- ||
- (isEmpty newwords && length usedletters==wordlength && not firstturn)
-
- unknownwords = filter (not o (seek lexicon)) newwords
-
- wordlength = size lastword
- firstturn = player1.points+player2.points==0
-
- totalscore = if (length usedletters==7) (playerscore+score+50) (playerscore+score)
- missingletters = removeMembers usedletters playerletters
- remainingletters = removeMembers playerletters usedletters
- (nb,possible,usedletters,score,newwords)
- = tryaddword board lastword (i,j) direction
- (i,j) = abs2rel (x,y)
-
-
- /***************************************************************************************************************
- arbitrate determines who's to play.
- ****************************************************************************************************************/
- arbitrate :: State (IOState State) -> (State,IOState State)
- arbitrate t=:{playmode,player,player1,player2,letterbox} io
- | isEmpty letterbox && not player1.placedword && not player2.placedword
- = (t, drawcommunication [text] (DisableTimer computerId io))
- with
- text = if (player1.points>player2.points) (toString Player1+++has_won)
- ( if (player2.points>player1.points) (toString Player2+++has_won)
- is_a_draw
- )
-
- | (player==Player1 && playmode==EndPlayer1 && player2.kind==Computer) ||
- (player==Player2 && playmode==EndPlayer2 && player1.kind==Computer)
- = ( nt
- , EnableTimer computerId (
- ChangeDialog scrabbleId [DisableDialogItems [3]] (
- drawletterbox letterbox io1))
- )
- with
- (boardletters,t1) = getboardletters t
- playerletters = if (nextplayer==Player1) player1.letters player2.letters
- initprogress = Letter firstletter initplacing
- sortedletters = sort (filter ((<>) ' ') (removeDup (playerletters++boardletters)))
- firstletter = if (isEmpty sortedletters) '@' (hd sortedletters)
- nt = {t1 & progress = initprogress
- , player = nextplayer
- , playmode = Playing
- }
-
- | playmode==EndPlayer1 || playmode==EndPlayer2
- = ( {t & player=nextplayer,playmode=Playing}
- , DisableTimer computerId (
- ChangeDialog scrabbleId [EnableDialogItems [3]] (
- drawletterbox letterbox io1))
- )
-
- | otherwise
- = (t,io)
- where
- nextplayer = otherplayer player
- io1 = drawcommunication [toString nextplayer+++is_move] io
-
-
- /***************************************************************************************************************
- The computer player (a timer) determines a move.
- ****************************************************************************************************************/
- computer :: TimerState State (IOState State) -> (State, IOState State)
- computer _ t=:{ board
- , dimensions
- , player
- , player1
- , player2
- , strength
- , playmode
- , lexicon
- , letterbox
- , progress
- , random
- } io
- | notyetready progress
- = (nt, drawprogress player progress newplacing io)
- with
- (newplacing,t2) = getnewplacing t1
- nt = {t2 & progress=newprogress}
-
- getnewplacing :: State -> (Placing,State)
- getnewplacing t=:{ board
- , dimensions
- , player
- , player1
- , player2
- , strength
- , lexicon
- , progress
- }
- | isMember (getletter progress) playerletters
- = (newmaximumplacings board lexicon playerletters dimensions progress strength firstturn,t)
- | otherwise
- = (newmaximumplacing board lexicon playerletters (horpos,verpos) progress strength firstturn,t)
- where
- playerletters
- | player==Player1 = player1.letters
- | otherwise = player2.letters
- horpos = getfreehorpositions board (getletter progress)
- verpos = getfreeverpositions board (getletter progress)
- firstturn = player1.points+player2.points==0
-
- newprogress
- | lastletter<>'z' && newletter<>'@'
- = Letter newletter newplacing
- | otherwise = Finish newplacing
- where
- lastletter = getletter progress
- nextletters = dropWhile (\l->(l<=lastletter)) (sort (filter ((<>) ' ') (removeDup (playerletters++boardletters))))
- newletter = if (isEmpty nextletters) '@' (hd nextletters)
-
- | wordfound
- = arbitrate ntready (drawplayerinfo player totalscore newplayerletters (
- drawcommunication (nr_new_words_placed ((length newwords)+1) [w:newwords]) (
- redrawboard nb io)))
-
- | otherwise
- = arbitrate ntready (drawplayerletters player newplayerletters (
- drawcommunication [toString Computer+++exchanges_letters] io))
-
- where
- ntready
- | player==Player1 = {nt1 & player1 = {nt1.player1 & letters=newplayerletters,points=totalscore,placedword=wordfound}
- , playmode= EndPlayer1}
- | otherwise = {nt1 & player2 = {nt1.player2 & letters=newplayerletters,points=totalscore,placedword=wordfound}
- , playmode= EndPlayer2}
- nt1 = {t1 & board = nb
- , letterbox = restletterbox
- , dimensions = newdimensions
- , random = rs1
- }
- (boardletters,t1) = getboardletters t
- placing = getplacing progress
- w = placing.word
- r = placing.dir
- pos = placing.pos
- (i,j) = pos
- wordlength = size w
- wordfound = wordlength>0
- (minx,maxx,miny,maxy) = dimensions
- newdimensions
- | not wordfound = dimensions
- | r==Hor = (min i minx, max (i+wordlength-1) maxx, min j miny, max j maxy)
- | otherwise = (min i minx, max i maxx, min j miny, max (j+wordlength-1) maxy)
- newplayerletters
- | not wordfound = replenishletters
- | otherwise = remainingletters++replenishletters
- (restletterbox,replenishletters,rs1)
- = grabletters
- grabletters
- | not wordfound = grab (playerletters++letterbox) 7 random
- | otherwise = grab letterbox (7-length remainingletters) random
-
- (playerletters,playerscore) = playerinfo
- playerinfo
- | player==Player1 = (player1.letters,player1.points)
- | otherwise = (player2.letters,player2.points)
- totalscore = playerscore+score
- remainingletters = removeMembers playerletters usedletters
-
- (nb,_,usedletters,score,newwords)
- = tryaddword board w pos r
-
- // Auxiliary functions:
- drawplayerletters :: Player [Char] (IOState t) -> IOState t
- drawplayerletters player letters io
- | player==Player1 = drawplayer1letters letters io
- | otherwise = drawplayer2letters letters io
-
- drawplayerinfo :: Player Int [Char] (IOState t) -> IOState t
- drawplayerinfo player score letters io
- | player==Player1 = drawplayer1score score (drawplayer1letters letters io)
- | otherwise = drawplayer2score score (drawplayer2letters letters io)
-
-
- /***************************************************************************************************************
- The help information should be displayed.
- ****************************************************************************************************************/
-
- help :: State (IOState State) -> (State,IOState State)
- help t=:{files} io
- # (files,io) = ShowHelp helpfilename files io
- = ({t & files=files},io)
-
-
- /***************************************************************************************************************
- The definition of the scrabble GUI.
- ****************************************************************************************************************/
-
- scrabblemenu (kind1,kind2)
- = PullDownMenu 1 scrabblemenutitle Able
- [ SubMenuItem 1 playersmenutitle Able
- [ MenuRadioItems initmarkid
- [ MenuRadioItem cpid (computer+++"/"+++person) NoKey Able (setplayerkinds Computer Person )
- , MenuRadioItem ccid (computer+++"/"+++computer) (Key 'C') Able (setplayerkinds Computer Computer)
- , MenuRadioItem ppid (person +++"/"+++person) (Key 'P') Able (setplayerkinds Person Person )
- , MenuRadioItem pcid (person +++"/"+++computer) NoKey Able (setplayerkinds Person Computer)
- ]]
- , MenuItem 310 newgametitle (Key 'n') Able new
- , MenuItem 2 quitgametitle (Key 'q') Able quit
- ]
- where
- computer = toString Computer
- person = toString Person
- cpid = 330; ccid = 331; ppid = 332; pcid = 333;
- initmarkid
- | kind1==Person && kind2==Computer = pcid
- | kind1==Computer&& kind2==Computer = ccid
- | kind1==Person && kind2==Person = ppid
- | otherwise = cpid
-
- setplayerkinds :: Playerkind Playerkind State (IOState State) -> (State,IOState State)
- setplayerkinds s1 s2 t=:{player1,player2} io = new {t & player1={player1 & kind=s1},player2={player2 & kind=s2}} io
-
- new :: State (IOState State) -> (State,IOState State)
- new t io
- # io = CloseDialog scrabbleId io
- (t,io) = initialisestate t io
- (t,io) = scrabblepanel t io
- (t,io) = arbitrate t io
- = (t,io)
-
- quit :: State (IOState State) -> (State,IOState State)
- quit t=:{wordsadded,lexicon} io
- | not wordsadded
- = (t,QuitIO io)
- # (decision,t,io) = OpenNotice save t io
- | decision==no
- = (t,QuitIO io)
- = ({t & files=writetree lexicon t.files},QuitIO io)
- where
- yes = 1
- no = 2
- save = Notice save_notice_text
- (NoticeButton yes save_notice_yes)
- [NoticeButton no save_notice_no]
-
-
- strengthmenu strength
- = PullDownMenu 2 strengthmenutitle Able
- [ MenuRadioItems initstrength
- [ MenuRadioItem maxid (toString Maximum) NoKey Able (setstrength Maximum)
- , MenuRadioItem mediumid (toString MediumStrength) NoKey Able (setstrength MediumStrength)
- , MenuRadioItem easyid (toString EasyStrength) NoKey Able (setstrength EasyStrength)
- , MenuRadioItem veryeasyid (toString VeryEasyStrength) NoKey Able (setstrength VeryEasyStrength)
- , MenuRadioItem firstid (toString First) NoKey Able (setstrength First)
- ]]
- where
- maxid = 320; firstid = 321; mediumid = 322; easyid = 323; veryeasyid = 324;
- initstrength
- | strength==Maximum = maxid
- | strength==First = firstid
- | strength==MediumStrength = mediumid
- | strength==EasyStrength = easyid
- | otherwise = veryeasyid
-
- setstrength :: Strength State (IOState State) -> (State,IOState State)
- setstrength nst t io = ({t & strength=nst},io)
-
-
- scrabblepanel :: State (IOState State) -> (State,IOState State)
- scrabblepanel t=:{lexicon,player1,player2,player,letterbox} io
- = (t,OpenDialog panel io)
- where
- panel = CommandDialog scrabbleId scrabbledialogtitle [DialogMargin (Pixel 10) (Pixel 10)] 3
- ([ Control 111 Left ((0,0),sizeletterbox) Unable (ListCS []) (letterboxlook letterbox) nofeel k`
- , Control 100 (RightTo 111) ((0,0),(boardwidth,boardheight)) (if personplaying Able Unable)
- (cs_tuple (boardwidth/2) (boardheight/2))
- (boardlook initboard (boardwidth,boardheight)) boardfeel k`
- , StaticText 101 (XOffset 100 (Pixel 10)) (toString Player1+++":")
- , Control 102 (YOffset 101 (Pixel 0)) ((0,0),sizeletters) Unable
- (StringCS (toString player1.letters)) (playerletterslook sizeletters) nofeel k`
- , StaticText 105 (XOffset 101 (Pixel 140)) (scrabbledialogscore+++":")
- , DynamicText 106 (YOffset 105 (Pixel 0)) (Pixel 40) (toString 0)
- , StaticText 103 (YOffset 102 (Pixel 10)) (toString Player2+++":")
- , Control 104 (YOffset 103 (Pixel 0)) ((0,0),sizeletters) Unable
- (StringCS (toString player2.letters)) (playerletterslook sizeletters) nofeel k`
- , StaticText 107 (XOffset 103 (Pixel 140)) (scrabbledialogscore+++":")
- , DynamicText 108 (YOffset 107 (Pixel 0)) (Pixel 40) (toString 0)
- , Control 110 (YOffset 104 (Pixel 20)) ((-2,-2),(displaywidth+2,displayheight+2)) Unable
- (ListCS (map toStringCS (scrabbledialoginittext lexicon)))
- (displaylook (displaywidth,displayheight)) nofeel k`
- ]
- ++
- (if (not personplaying)
- []
- [ StaticText 109 (YOffset 110 (Pixel 20)) (scrabbledialogword+++":")
- , EditText 200 (XOffset 109 (Pixel 5)) (Pixel 80) 1 ""
- , StaticText 0 (Below 109) scrabbledialogdirection
- , RadioButtons 1 (Below 200) (Columns 1) 201
- [ RadioItem 201 (toString Hor) Able k`
- , RadioItem 202 (toString Ver) Able k`
- ]
- , DialogButton 3 (Below 1) scrabbledialogplaceword selectstateplaceword placeword
- ]))
- nofeel _ cs = (cs,[])
- k` _ x = x
- cs_tuple x y = PairCS (IntCS x) (IntCS y)
- sizeletterbox = (squarewidth*4,squareheight*15)
- sizeletters = (squarewidth*7,squareheight)
- personplaying = player1.kind==Person || player2.kind==Person
- selectstateplaceword
- | player==Player1 && player1.kind==Person
- = Able
- | player==Player2 && player2.kind==Person
- = Able
- | otherwise = Unable
-
- boardfeel :: MouseState ControlState -> (ControlState,[DrawFunction])
- boardfeel ((x,y),ButtonDown,_) oldcs
- = (newcs,drawfocus False oldcs ++ drawfocus True newcs)
- where
- newcs = cs_tuple x y
- boardfeel _ cs
- = (cs,[])
-
- newwordspanel words info
- = CommandDialog toevoegId addwordstitle [] 202
- [ StaticText 0 Center mededeling1
- , StaticText 1 Center mededeling2
- , ScrollingList 300 Center (Pixel 260) Able (max 10 10) (hd words) words (\_ ds->ds)
- , DialogButton 2 Center addwords_no Able (\_ s io->(s,CloseActiveDialog io))
- , DialogButton 202 (RightTo 2) addwords_yes Able (add words info)
- ]
- where
- (mededeling1,mededeling2) = addwordsheading (length words)
-
- add :: [Word] DialogInfo DialogInfo State (IOState State) -> (State,IOState State)
- add words info _ t=:{lexicon} io
- = placeword info {t & lexicon=addwordstotree lexicon words,wordsadded=True} (CloseActiveDialog io)
-